<?php
/**
 * 微信公众号主类
 * 处理微信服务器的消息和事件
 */
class HYWL_Wechat {
    
    private $options;
    private $token;
    private $appid;
    private $appsecret;
    private $logger;
    
    /**
     * 构造函数
     */
    public function __construct() {
        $this->options = get_option('hywl_wechat_options', array());
        $this->token = isset($this->options['token']) ? $this->options['token'] : '';
        $this->appid = isset($this->options['appid']) ? $this->options['appid'] : '';
        $this->appsecret = isset($this->options['appsecret']) ? $this->options['appsecret'] : '';
        
        // 初始化日志记录器
        $this->logger = new HYWL_Wechat_Logger();
    }
    
    /**
     * 处理微信服务器请求
     */
    public function handle_request() {
        // 记录请求信息
        $request_info = json_encode([
            'URI' => $_SERVER['REQUEST_URI'],
            'METHOD' => $_SERVER['REQUEST_METHOD'],
            'QUERY' => $_GET,
            'HEADERS' => getallheaders(),
        ]);
        $this->logger->info('收到新的微信服务器请求: ' . $request_info);
        hywl_wechat_debug_log('收到微信请求: ' . $request_info);
        
        // 直接发送测试响应，查看是否能正常返回
        if (isset($_GET['test']) && $_GET['test'] == '1') {
            $this->logger->info('发送测试响应');
            echo "微信公众号接口测试成功！";
            exit;
        }
        
        // 服务器配置验证
        if (isset($_GET['echostr'])) {
            $this->logger->info('微信服务器验证请求');
            hywl_wechat_debug_log('接收到微信验证请求');
            $this->verify_server();
            exit;
        }
        
        // 接收消息
        $postStr = file_get_contents('php://input');
        $this->logger->info('接收原始POST数据: ' . (empty($postStr) ? '空' : $postStr));
        hywl_wechat_debug_log('接收原始POST数据: ' . (empty($postStr) ? '空' : $postStr));
        
        if (empty($postStr)) {
            $this->logger->error('接收到空请求');
            // 发送测试响应，确认接口能正常工作
            echo "接口正常，但未收到消息数据";
            exit;
        }
        
        // 记录接收到的原始XML
        $this->logger->info('接收到的原始XML: ' . $postStr);
        
        // 解析XML消息
        libxml_use_internal_errors(true);
        $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
        if (!$postObj) {
            $errors = libxml_get_errors();
            $error_msg = 'XML解析失败：';
            foreach ($errors as $error) {
                $error_msg .= " {$error->message} (行 {$error->line})";
            }
            $this->logger->error($error_msg);
            hywl_wechat_debug_log($error_msg);
            libxml_clear_errors();
            echo "XML解析失败";
            exit;
        }
        
        // 处理不同消息类型
        $msgType = (string)$postObj->MsgType;
        $this->logger->info('接收到的消息类型: ' . $msgType);
        
        switch ($msgType) {
            case 'text':
                $this->logger->info('处理文本消息，FromUser: ' . (string)$postObj->FromUserName . ', Content: ' . (string)$postObj->Content);
                $this->handle_text_message($postObj);
                break;
            case 'event':
                $this->logger->info('处理事件消息，FromUser: ' . (string)$postObj->FromUserName . ', Event: ' . (string)$postObj->Event);
                $this->handle_event_message($postObj);
                break;
            default:
                $this->logger->warning('收到未处理的消息类型: ' . $msgType);
                $this->response_default_message($postObj);
                break;
        }
        
        exit;
    }
    
    /**
     * 验证服务器配置
     */
    private function verify_server() {
        $signature = isset($_GET['signature']) ? $_GET['signature'] : '';
        $timestamp = isset($_GET['timestamp']) ? $_GET['timestamp'] : '';
        $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : '';
        $echostr = isset($_GET['echostr']) ? $_GET['echostr'] : '';
        
        $this->logger->info("验证服务器请求: signature={$signature}, timestamp={$timestamp}, nonce={$nonce}");
        
        if (empty($signature) || empty($timestamp) || empty($nonce) || empty($echostr)) {
            $this->logger->error("验证请求参数不完整");
            exit('Invalid request');
        }
        
        $tmpArr = array($this->token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);
        
        $this->logger->info("计算的签名: {$tmpStr}, 微信签名: {$signature}");
        
        if ($tmpStr == $signature) {
            $this->logger->info("验证成功，返回echostr: {$echostr}");
            echo $echostr;
        } else {
            $this->logger->error("验证失败，签名不匹配");
            echo 'Failed to verify signature';
        }
        
        exit;
    }
    
    /**
     * 处理文本消息
     */
    private function handle_text_message($postObj) {
        $fromUsername = (string)$postObj->FromUserName;
        $toUsername = (string)$postObj->ToUserName;
        $keyword = trim((string)$postObj->Content);
        
        $this->logger->info("处理来自用户 {$fromUsername} 的关键词: {$keyword}");
        
        if (empty($keyword)) {
            $this->logger->warning("关键词为空，返回默认消息");
            $this->response_default_message($postObj);
            return;
        }
        
        // 搜索WordPress网站内容
        $this->logger->info("开始搜索关键词: {$keyword}");
        $searchResults = $this->search_wordpress_content($keyword);
        
        // 构建回复消息
        if (empty($searchResults)) {
            // 未找到相关内容
            $this->logger->info("未找到关键词 {$keyword} 的相关内容");
            $contentStr = isset($this->options['not_found_msg']) ? $this->options['not_found_msg'] : '未找到相关内容';
            $this->response_text_message($postObj, $contentStr);
        } else {
            // 找到相关内容，返回图文消息
            $this->logger->info("找到关键词 {$keyword} 的相关内容，共 " . count($searchResults) . " 条结果");
            $this->response_news_message($postObj, $searchResults);
        }
    }
    
    /**
     * 处理事件消息
     */
    private function handle_event_message($postObj) {
        $event = strtolower((string)$postObj->Event);
        
        switch ($event) {
            case 'subscribe':
                // 用户关注事件
                $contentStr = isset($this->options['welcome_msg']) ? $this->options['welcome_msg'] : '欢迎关注！';
                $this->response_text_message($postObj, $contentStr);
                break;
            default:
                $this->response_default_message($postObj);
                break;
        }
    }
    
    /**
     * 搜索WordPress内容
     */
    private function search_wordpress_content($keyword) {
        $search_limit = isset($this->options['search_limit']) ? intval($this->options['search_limit']) : 5;
        $this->logger->info("开始WordPress内容搜索，关键词: {$keyword}, 限制: {$search_limit}");
        
        // 使用WordPress内置搜索功能
        $args = array(
            's' => $keyword,
            'post_type' => 'post',
            'post_status' => 'publish',
            'posts_per_page' => $search_limit
        );
        
        $this->logger->info("WP_Query参数: " . json_encode($args));
        $query = new WP_Query($args);
        $this->logger->info("查询到 {$query->post_count} 篇文章");
        $results = array();
        
        if ($query->have_posts()) {
            while ($query->have_posts()) {
                $query->the_post();
                $post_id = get_the_ID();
                $title = get_the_title();
                
                $this->logger->info("处理搜索结果: ID={$post_id}, 标题={$title}");
                
                // 获取特色图片
                $thumb = get_the_post_thumbnail_url($post_id, 'medium');
                if (empty($thumb)) {
                    $this->logger->info("文章 {$post_id} 没有特色图片，使用默认图片");
                    $thumb = HYWL_WECHAT_PLUGIN_URL . 'assets/default-thumb.jpg';
                }
                
                // 获取摘要
                $excerpt = get_the_excerpt();
                if (empty($excerpt)) {
                    $this->logger->info("文章 {$post_id} 没有摘要，从内容中提取");
                    $content = get_the_content();
                    $excerpt = wp_trim_words($content, 55, '...');
                }
                
                $permalink = get_permalink();
                $this->logger->info("添加搜索结果: ID={$post_id}, URL={$permalink}");
                
                $results[] = array(
                    'title' => $title,
                    'description' => $excerpt,
                    'picurl' => $thumb,
                    'url' => $permalink
                );
            }
            wp_reset_postdata();
        }
        
        return $results;
    }
    
    /**
     * 清理和截断字符串以便在微信XML中安全使用
     * @param string $string 原始字符串
     * @param int $length 截断长度
     * @return string 清理后的字符串
     */
    private function wechat_safe_string($string, $length = 60) {
        // 1. 剥离所有HTML和PHP标签
        $string = strip_tags($string);

        // 2. 移除可能存在的CDATA标签，防止嵌套
        $string = str_replace(array('<![CDATA[', ']]>'), '', $string);
        
        // 3. 移除XML 1.0中无效的控制字符
        $string = preg_replace('/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]/', '', $string);
        
        // 4. 去除首尾空白
        $string = trim($string);

        // 5. 使用mb_substr进行安全截断
        if (mb_strlen($string, 'utf-8') > $length) {
            $string = mb_substr($string, 0, $length, 'utf-8') . '...';
        }
        
        return $string;
    }
    
    /**
     * 回复文本消息
     */
    private function response_text_message($postObj, $content) {
        $fromUsername = (string)$postObj->FromUserName;
        $toUsername = (string)$postObj->ToUserName;
        $time = time();
        
        $textTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[text]]></MsgType>
            <Content><![CDATA[%s]]></Content>
            </xml>";
            
        $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $content);
        
        // 记录响应内容
        $this->logger->info("回复文本消息: {$resultStr}");
        hywl_wechat_debug_log("回复文本消息: {$resultStr}");
        
        // 确保响应正确发送
        header('Content-Type: text/xml; charset=utf-8');
        echo $resultStr;
        
        // 记录响应已发送
        $this->logger->info("响应已发送");
        hywl_wechat_debug_log("响应已发送");
    }
    
    /**
     * 回复图文消息
     */
    private function response_news_message($postObj, $articles) {
        $fromUsername = (string)$postObj->FromUserName;
        $toUsername = (string)$postObj->ToUserName;
        $time = time();
        $articleCount = count($articles);
        
        $this->logger->info("准备发送图文消息，共 {$articleCount} 条");
        hywl_wechat_debug_log("准备发送图文消息，共 {$articleCount} 条");
        
        $newsTpl = "<xml>
            <ToUserName><![CDATA[%s]]></ToUserName>
            <FromUserName><![CDATA[%s]]></FromUserName>
            <CreateTime>%s</CreateTime>
            <MsgType><![CDATA[news]]></MsgType>
            <ArticleCount>%s</ArticleCount>
            <Articles>%s</Articles>
            </xml>";
            
        $itemTpl = "<item>
            <Title><![CDATA[%s]]></Title>
            <Description><![CDATA[%s]]></Description>
            <PicUrl><![CDATA[%s]]></PicUrl>
            <Url><![CDATA[%s]]></Url>
            </item>";
            
        $itemStr = '';
        foreach ($articles as $article) {
            $this->logger->info("添加图文项: " . $article['title']);
            
            $safe_title = $this->wechat_safe_string($article['title'], 80);
            $safe_description = $this->wechat_safe_string($article['description'], 120);

            $itemStr .= sprintf($itemTpl, $safe_title, $safe_description, $article['picurl'], $article['url']);
        }
        
        $resultStr = sprintf($newsTpl, $fromUsername, $toUsername, $time, $articleCount, $itemStr);
        
        // 记录响应内容
        $this->logger->info("回复图文消息: " . substr($resultStr, 0, 500) . (strlen($resultStr) > 500 ? '...(已截断)' : ''));
        hywl_wechat_debug_log("回复图文消息: " . substr($resultStr, 0, 500) . (strlen($resultStr) > 500 ? '...(已截断)' : ''));
        
        // 确保响应正确发送
        header('Content-Type: text/xml; charset=utf-8');
        echo $resultStr;
        
        // 记录响应已发送
        $this->logger->info("图文响应已发送");
        hywl_wechat_debug_log("图文响应已发送");
    }
    
    /**
     * 回复默认消息
     */
    private function response_default_message($postObj) {
        $contentStr = isset($this->options['not_found_msg']) ? $this->options['not_found_msg'] : '未找到相关内容';
        $this->response_text_message($postObj, $contentStr);
    }
} 